#include "jawt_md.h"
#include <windows.h>
#include "com_tgjorgoski_window_MyAppBar.h"
#define APPBAR_CALLBACK WM_APP+1

DWORD threadPreviouslyFocused;
HWND previousFocused;
HWND windowHandle;
WNDPROC originalWindowProcedure;
BOOL firstTime = TRUE;
UINT g_uSide;

BOOL AppBar_Register(HWND hWnd)
{
	APPBARDATA abd;
	abd.cbSize = sizeof(APPBARDATA);
	abd.hWnd = hWnd;
	abd.uCallbackMessage = APPBAR_CALLBACK;
	return SHAppBarMessage(ABM_NEW, &abd);
}

BOOL AppBar_UnRegister()
{
	APPBARDATA abd;
	abd.cbSize = sizeof(APPBARDATA);
	abd.hWnd = windowHandle;
	SHAppBarMessage(ABM_REMOVE, &abd);
	return TRUE;
}

JNIEXPORT void JNICALL Java_com_tgjorgoski_window_MyAppBar_unSetBar(JNIEnv * env, jobject obj)
{
	AppBar_UnRegister();
}

JNIEXPORT void JNICALL Java_com_tgjorgoski_window_MyAppBar_getFocus(JNIEnv * env, jobject obj) {
	
	/*
	GUITHREADINFO lpgui;
	lpgui.cbSize = sizeof(LPGUITHREADINFO);
	BOOL succ = GetGUIThreadInfo(NULL, &lpgui);
	if (succ!=0) {
		previousFocused=lpgui.hwndFocus;
	} else {
		::MessageBox(NULL,L"Problem",L"DLL Run time Error",MB_OK|MB_ICONERROR);
	}*/

	/*previousFocused = GetForegroundWindow();

	DWORD processID;
	DWORD threadID = GetWindowThreadProcessId(previousFocused, &processID);
	if (threadID!=threadPreviouslyFocused) {
		DWORD curThread = GetCurrentThreadId();
		if (threadPreviouslyFocused!=NULL) {
			AttachThreadInput(curThread, threadPreviouslyFocused, FALSE);
		}
		threadPreviouslyFocused=threadID;
		//attach to this new foreground tread
		AttachThreadInput(curThread, threadID, TRUE);
	}

	SetForegroundWindow(windowHandle);*/

	previousFocused = GetForegroundWindow();
	DWORD processID;
	DWORD threadID = GetWindowThreadProcessId(previousFocused, &processID);
	DWORD curThread = GetCurrentThreadId();
	if (threadID!=NULL) {
		AttachThreadInput(curThread, threadID, TRUE);
	}
	SetForegroundWindow(windowHandle);
	if (threadID!=NULL) {
		AttachThreadInput(curThread, threadID, FALSE);
	}

}

JNIEXPORT void JNICALL Java_com_tgjorgoski_window_MyAppBar_returnFocus(JNIEnv * env, jobject obj) {
	/*SetForegroundWindow(previousFocused);*/

	DWORD processID;
	DWORD threadID = GetWindowThreadProcessId(previousFocused, &processID);
	DWORD curThread = GetCurrentThreadId();
	if (threadID!=NULL) {
		AttachThreadInput(curThread, threadID, TRUE);
	}
	SetForegroundWindow(previousFocused);
	if (threadID!=NULL) {
		AttachThreadInput(curThread, threadID, FALSE);
	}

	
}


void AppBar_QuerySetPos(UINT uEdge, LPSIZE lpsize, PAPPBARDATA pabd)
{
	int iHeight = 0;
	int iWidth = 0;

	pabd->uEdge = uEdge;

	pabd->rc.top = 0;
	pabd->rc.bottom = GetSystemMetrics(SM_CYSCREEN);
	pabd->rc.left = 0;
	pabd->rc.right = GetSystemMetrics(SM_CXSCREEN);

	switch(uEdge){
		case ABE_LEFT:
			pabd->rc.right=pabd->rc.left+lpsize->cx;
			break;
		case ABE_RIGHT:
			pabd->rc.left=pabd->rc.right-lpsize->cx;
			break;
		case ABE_TOP:
			pabd->rc.bottom=pabd->rc.top+lpsize->cy;
			break;
		case ABE_BOTTOM:
			pabd->rc.top=pabd->rc.bottom-lpsize->cy;
			break;
	}

	SHAppBarMessage(ABM_QUERYPOS, pabd);

	switch (uEdge) {
		case ABE_LEFT:
			pabd->rc.right = pabd->rc.left + lpsize->cx;
			break;
		case ABE_RIGHT:
			pabd->rc.left = pabd->rc.right - lpsize->cx;
			break;
		case ABE_TOP:
			pabd->rc.bottom = pabd->rc.top + lpsize->cy;
			break;
		case ABE_BOTTOM:
			pabd->rc.top = pabd->rc.bottom - lpsize->cy;
			break;
	}
	SHAppBarMessage(ABM_SETPOS, pabd);
	MoveWindow(pabd->hWnd, pabd->rc.left, pabd->rc.top,
	pabd->rc.right - pabd->rc.left,
	pabd->rc.bottom - pabd->rc.top, TRUE);
}

void AppBar_PosChanged(HWND hWnd)
{
	RECT rc;
	SIZE size;
	APPBARDATA abd;
	abd.cbSize = sizeof(abd);
	abd.hWnd = hWnd;
	GetWindowRect(hWnd,&rc);
	size.cx=rc.right-rc.left;
	size.cy=rc.bottom-rc.top;
	AppBar_QuerySetPos(g_uSide, &size, &abd);
}
void AppBar_Activate(HWND hWnd)
{
	APPBARDATA abd;
	abd.cbSize = sizeof(APPBARDATA);
	abd.hWnd = hWnd;
	abd.lParam = 0;
	SHAppBarMessage(ABM_ACTIVATE, &abd);
}
void AppBar_WindowPosChanged(HWND hWnd)
{
	APPBARDATA abd;
	abd.cbSize = sizeof(APPBARDATA);
	abd.hWnd = hWnd;
	abd.lParam = 0;
	SHAppBarMessage(ABM_WINDOWPOSCHANGED, &abd);
}
void AppBar_Callback(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
	switch(wParam)
	{
		case ABN_POSCHANGED:
		AppBar_PosChanged(hWnd);
		break;
	}
}
int CALLBACK WndProc(HWND hWnd, UINT wMessage,WPARAM wParam, LPARAM lParam)
{
	switch (wMessage)
	{
		case WM_ACTIVATE:
			AppBar_Activate(hWnd);
			break;

			/*
		case WM_WINDOWPOSCHANGED:
			AppBar_WindowPosChanged(hWnd);
			break;
		case WM_EXITSIZEMOVE:
			AppBar_PosChanged(hWnd);
			break;
		case APPBAR_CALLBACK:
			AppBar_Callback(hWnd,wParam,lParam);
			break;*/
	}
	return CallWindowProc(originalWindowProcedure, hWnd, wMessage, wParam, lParam);
}

JNIEXPORT void JNICALL Java_com_tgjorgoski_window_MyAppBar_setAsBar(JNIEnv *env, jobject obj, jstring title, jint position)
{
	switch(position)
	{
		case 1:
			g_uSide = ABE_LEFT;
			break;
		case 2:
			g_uSide = ABE_TOP;
			break;
		case 3:
			g_uSide = ABE_RIGHT;
			break;
		case 4:
			g_uSide = ABE_BOTTOM;
			break;
	}
	const char *str = (env)->GetStringUTFChars(title, 0);
	wchar_t strTitle[128];
	mbstowcs(strTitle, str, strlen(str)+1);

	HWND hwnd = FindWindow(NULL,strTitle);
	if(hwnd == NULL) return;
	windowHandle = hwnd;
	ShowWindow(windowHandle,SW_HIDE);
	(env)->ReleaseStringUTFChars(title, str);

	//set it as a tool window(don't show in taskbar), and also set it to be topmost
	SetWindowLong(windowHandle,GWL_EXSTYLE,WS_EX_TOOLWINDOW);
	SetWindowPos(windowHandle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

	WNDPROC wndProc = (WNDPROC) SetWindowLong(windowHandle,GWL_WNDPROC,(LONG) WndProc);
	originalWindowProcedure = wndProc;
	AppBar_Register(windowHandle);
	AppBar_PosChanged(windowHandle);
	ShowWindow(windowHandle,SW_SHOW);
}